package com.clx.nettry;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.Serializable;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class AppClient implements Serializable {

    //整体流程总结
    //初始化 “线程池”，供客户端处理 I/O 操作。
    //通过Bootstrap组装客户端的核心组件（指定线程池、服务端地址、Channel 类型、处理器）。
    //异步发起连接，再同步等待连接完成。
    //连接成功后，向服务端写数据。
    //同步等待连接关闭（让客户端不立即退出，可接收服务端后续响应）
    public void run(){
        // 定义线程池 EventLoopGroup
        //EventLoopGroup是 Netty 的线程池，负责处理网络 I/O 操作（如读写数据、连接管理）
        //NioEventLoopGroup基于 Java NIO（非阻塞 I/O）实现，能高效处理大量并发连接（利用 “多路复用”，一个线程可管理多个连接
        NioEventLoopGroup group = new NioEventLoopGroup();

        //启动一个客户端需要一个辅助类。bootstrap
        // Bootstrap：客户端启动辅助类
        Bootstrap bootstrap =new Bootstrap();
        try {
        //配置 Bootstrap 的核心参数（链式调用)
        //.group(group)：指定客户端使用的线程池（即上面创建的NioEventLoopGroup），让线程池处理客户端的 I/O 事件。
        bootstrap = bootstrap.group(group)
                //.remoteAddress(...)：设置服务端的地址和端口（这里连接本地 8080 端口的服务端）。
                .remoteAddress(new InetSocketAddress(8080))
                // 选择初始化一个什么样的channel，Channel是 Netty 对 “网络连接” 的抽象，
                // NioSocketChannel基于 Java NIO 实现，用于客户端与服务端的 TCP 连接。
                .channel(NioSocketChannel.class)
                //设置Channel 的处理器（ChannelHandler）。
                // 这里用ChannelInitializer（特殊的 Handler），
                // 它的作用是：在 Channel 初始化时，动态添加其他业务 Handler（比如编解码、消息处理的 Handler）
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception{
                        //把自定义的处理器 MyChannelHandler2 添加到当前连接的 “处理器管道（ChannelPipeline）” 末尾，
                        // 这样后续该连接上的网络事件（比如接收客户端消息、发送响应、处理异常等），就会由 MyChannelHandler2 来处理。
                        socketChannel.pipeline().addLast(new MyChannelHandler2());
                    }
                });

        // 尝试连接服务器
        ChannelFuture channelFuture = null;
            //bootstrap.connect()：异步发起连接请求（Netty 是 “异步框架”，调用后立即返回，不会阻塞当前线程）。
            //ChannelFuture：表示 “异步操作的结果”，可以通过它监听 “连接是否成功”“连接何时完成” 等事件。
            //.sync()：同步等待连接完成。调用后，当前线程会阻塞，直到连接操作完成（成功或失败）。
            channelFuture = bootstrap.connect().sync();
            //获取channel,并且写出数据
            //channelFuture.channel()：获取已建立的 Channel（即客户端与服务端的连接）。
            //writeAndFlush(...)：向服务端写数据并强制刷新缓冲区（确保数据被立即发送）。
            //Unpooled：Netty 提供的工具类，用于创建 “字节缓冲区（ByteBuf）”。
            //copiedBuffer(...)：把字符串转换成 Netty 的ByteBuf格式，让 Netty 能处理并发送
            channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer("hello nettry".getBytes(StandardCharsets.UTF_8)));

            //阻塞程序，等待接收消息
            //closeFuture()：返回一个ChannelFuture，用于监听Channel 的 “关闭事件”（比如服务端断开连接、客户端主动关闭）。
            //.sync()：同步等待 Channel 关闭。调用后，当前线程会阻塞，直到连接被关闭（这样客户端程序不会立即退出，能等待服务端的响应或连接自然结束）。
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            try {
                //shutdownGracefully()：启动 “优雅关闭” 流程 —— 停止接收新任务，同时把已有的任务（比如网络连接、待处理的 IO 操作）妥善处理完。
                //sync()：让当前线程 “等待”，直到 “优雅关闭” 的整个过程完成，确保所有资源（线程、网络连接等）都被有序释放，
                // 避免 abrupt（突然、粗暴）关闭导致的问题。
                group.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new AppClient().run();
    }
}
